#ifndef WRAPGRAPHINVIRTUALGENERATOR_H_
#define WRAPGRAPHINVIRTUALGENERATOR_H_

#include "IGraphGenerator.h"

#include <vector>
#include <algorithm>

#include "graph_support/IGraph.h"
#include "graph_support/impls/wrap_igraph/WrapIGraph.h"


namespace
{

static void deleteGraph( GRAPH_SUPPORT_NS::Graph * abstractGraphPtr ) {
	delete abstractGraphPtr;
}

}

namespace native_orbitor
{

// TODO: use usual decorator pattern
// TODO: may be unified polimorphic holder will help here
template< typename SubGeneratorT >
class WrapGraphInVirtualGenerator : public native_orbitor::IGraphGenerator
{
public:
	virtual std::auto_ptr< GraphPointerGuard > generateGraph(
			SettingsMap settingsMap )
	{
		using namespace GRAPH_SUPPORT_NS;
		using namespace GRAPH_SUPPORT_NS::impls::wrap_igraph;

		typedef typename SubGeneratorT::Graph SrcGraph;
		typedef typename SrcGraph::GrVertex GrVertex;
		typedef typename SrcGraph::GrEdgePtr GrEdgePtr;
		typedef typename SrcGraph::VertexIterator VertexIterator;
		typedef typename SrcGraph::EdgeIterator EdgeIterator;
		typedef typename SrcGraph::EdgeAttributes EdgeAttributes;
		typedef typename IGraph::EdgeAttributesImpl< EdgeAttributes >::CpAttributes IEdgeAttributesImpl;
		// TODO: graph name convention
		typedef WrapIGraph< EdgeAttributes > TheWrapGraph;
		typedef typename TheWrapGraph::IGraphPtr IGraphPtr;

		std::auto_ptr< GraphPointerGuard > srcGrAPtr = subGenerator.generateGraph( settingsMap );
		SrcGraph * srcGrPtr = dynamic_cast< SrcGraph * >( srcGrAPtr->getAbstractGraphPtr() );
		assert( srcGrPtr );
		SrcGraph & srcGr = * srcGrPtr;

		std::vector< GrVertex > vertices( srcGr.getVertexCount() );
		std::copy( srcGr.getVerticesBeg(), srcGr.getVerticesEnd(), vertices.begin() );

		IGraphPtr resultSPtr( new SrcGraph( vertices ) );
		IGraph & result = * resultSPtr;

		VertexIterator vsit = srcGr.getVerticesEnd();
		for ( VertexIterator vit = srcGr.getVerticesBeg(); vit != vsit; ++vit )
		{
			// TODO getEdgs vs getEdges -- remove ambigous
			EdgeIterator esit = srcGr.getEdgsEnd( * vit );
			for ( EdgeIterator eit = srcGr.getEdgsBeg( * vit ); eit != esit; ++eit )
			{
				GrEdgePtr eptr = * eit;
				EdgeAttributes & attributes = eptr->getAttributes();
				IGraph::IEdgeAttributesPtr attributesPtr( new IEdgeAttributesImpl( attributes ) );
				result.iaddEdge(
						srcGr.vert2num( eptr->beg() ),
						srcGr.vert2num( eptr->end() ),
						attributesPtr );
			}
		}

		return std::auto_ptr< GraphPointerGuard >( new GraphPointerGuard( new TheWrapGraph( resultSPtr ), & deleteGraph ) );
	}

private:
	SubGeneratorT subGenerator;
};

}

#endif /* WRAPGRAPHINVIRTUALGENERATOR_H_ */
